﻿/*
 *	Copyright (c) 2009 Queensland University of Technology. All rights reserved.
 *	The QUT Bioinformatics Collection is open source software released under the 
 *	Microsoft Public License (Ms-PL): http://www.microsoft.com/opensource/licenses.mspx.
 */
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Navigation;
using System.Windows.Threading;
using System.Xml.Linq;
using System.IO;
using System.ServiceModel;
using BlastExplorer.GenomeDB;
using QUT.Bio.Util;

namespace BlastExplorer {
	/// <summary>
	/// Gets a GI number and Protein from GenomeDB.
	/// </summary>
	public partial class GenomeDBLoader: Window {
		static private string accession = "NC_000117.1";
		static private string locusTag = "CT323";
		static private string queryProtein;
		static private decimal queryGI;
		static private string queryDefinition;

		private StatusBar statusBar;

		public GenomeDBLoader () {
			InitializeComponent();

			accessionField.Text = accession;
			locusTagField.Text = locusTag;
			eValueCutoffField.Text = Settings.DefaultEValue.ToString();
			cddEValueCutoffField.Text = Settings.DefaultCddEValue.ToString();
			hitListSizeField.Text = Settings.DefaultHitListSize.ToString();
		}

		public void Initialise (
			StatusBar statusBar,
			double eValueCutoff,
			double cddEValueCutoff,
			int hitListSize,
			bool useBrowserProxy,
			Taxon [] selectedTaxa			
		) {
			this.statusBar = statusBar;
			useBrowserProxyField.IsChecked = useBrowserProxy;
			eValueCutoffField.Text = eValueCutoff.ToString();
			cddEValueCutoffField.Text = cddEValueCutoff.ToString();
			hitListSizeField.Text = hitListSize.ToString();
			taxonField.SelectedTaxa = selectedTaxa;
		}

		#region Property: SelectedTaxa
		/// <summary>
		/// Gets a new array containing the tax id's of the selected taxa.
		/// </summary>


		public Taxon[] SelectedTaxa {
			get {
				return taxonField.SelectedTaxa;
			}
		}
		#endregion

		#region Property: EValueCutoff
		/// <summary>
		/// Gets the E-value cutoff, or the dafault;
		/// </summary>

		public double EValueCutoff {
			get {
				try {
					return double.Parse( eValueCutoffField.Text.Trim() );
				}
				catch {
					return Settings.DefaultEValue;
				}
			}
		}
		#endregion

		#region Property: CddEValueCutoff
		/// <summary>
		/// Gets the Cdd E-value cutoff.
		/// </summary>

		public double CddEValueCutoff {
			get {
				try {
					return double.Parse( cddEValueCutoffField.Text );
				}
				catch {
					return Settings.DefaultCddEValue;
				}
			}
		} 
		#endregion

		#region Property: HitListSize
		/// <summary>
		/// Gets the hit list size.
		/// </summary>

		public int HitListSize {
			get {
				try {
					return int.Parse( hitListSizeField.Text );
				}
				catch {
					return Settings.DefaultHitListSize;
				}
			}
		}
		#endregion
		
		static public string QueryProtein {
			get {
				return queryProtein;
			}
		}

		static public decimal QueryGI {
			get {
				return queryGI;
			}
		}

		static public string QueryDefinition {
			get {
				return queryDefinition;
			}
		}

		public bool UseBrowserProxy {
			get {
				return useBrowserProxyField.IsChecked == true;
			}
		}

		private void Cancel_Click ( object sender, RoutedEventArgs e ) {
			this.DialogResult = false;
		}

		private void Load_Click ( object sender, RoutedEventArgs e ) {
			statusBar.Visibility = Visibility.Visible;

			GetTranslationFromGenomeDB(
				delegate() {
					statusBar.StopProgress();
					statusBar.Clear();

					accession = accessionField.Text.Trim();
					locusTag = locusTagField.Text.Trim();

					this.DialogResult = true;
				},
				delegate() {
					statusBar.StopProgress();
					statusBar.WriteLine( "Unable to communicate with GenomeDB." );
					Debug.WriteLine( "GetTranslationFromGenomeDB failed." );
				}
			);
		}

		private decimal GetGI ( Dictionary<string, List<string>> geneData ) {
			decimal result = 0;

			if ( geneData.ContainsKey( "db_xref" ) ) {
				foreach ( string s in geneData["db_xref"] ) {
					if ( s.StartsWith( "GI:" ) ) {
						try {
							result = decimal.Parse( s.Substring( 3 ) );
						}
						catch {
						}
					}
				}
			}

			return result;
		}

		private string GetProperty ( Dictionary<string, List<string>> geneData, string propertyName ) {
			string p = null;

			if ( geneData.ContainsKey( propertyName ) ) {
				p = geneData[propertyName][0];
			}

			return p;
		}

		private void GetTranslationFromGenomeDB ( Action onSuccess, Action onFailure ) {
			try {
				string queryAccession =  accessionField.Text.Trim().ToUpper();
				string queryLocusTag = locusTagField.Text.Trim().ToUpper();

				GeneIdentifier geneIdentifier = new GeneIdentifier {
					AccessionVersion = queryAccession,
					ID = queryLocusTag,
					IdType = GeneIdentifierType.LocusTag
				};

				statusBar.WriteLine( "Communicating with GenomeDB" );
				statusBar.StartProgress();

				ServiceSoapClient sc = new ServiceSoapClient();

				sc.getGeneAttributeASCompleted += delegate( object sender_, getGeneAttributeASCompletedEventArgs args ) {
					Dictionary<string, List<string>> queryGeneData = Deserialize( args.Result );
					queryGI = GetGI( queryGeneData );
					queryProtein = GetProperty( queryGeneData, "translation" );
					queryDefinition = GetProperty( queryGeneData, "product" );
					onSuccess();
				};

				sc.getGeneAttributeASAsync( geneIdentifier );
			}
			catch ( Exception ex ) {
				Debug.WriteLine( ex.ToString() );
				onFailure();
			}
		}

		/// <summary>
		/// Gets a web service end point for GenomeDB.
		/// </summary>
		/// <returns></returns>

		private ServiceSoapClient GetSoapClient () {
			BasicHttpBinding binding = new BasicHttpBinding {
				MaxReceivedMessageSize = int.MaxValue,
				MaxBufferSize = int.MaxValue
			};

			binding.ReaderQuotas.MaxArrayLength = int.MaxValue;
			binding.ReaderQuotas.MaxStringContentLength = int.MaxValue;
			binding.ReaderQuotas.MaxBytesPerRead = int.MaxValue;

			ServiceSoapClient res = null;

			res = new ServiceSoapClient(
				binding,
				new EndpointAddress( Settings.GenomeDBWebServiceAddress )
			);
			res.InnerChannel.OperationTimeout = new TimeSpan( 0, 2, 0 );

			return res;
		}

		#region Method: Deserialize
		/// <summary>
		/// Deserializes the Xml document returned by GenomeDB into an attribute collection.
		/// </summary>
		/// <param name="xml"></param>
		/// <returns></returns>

		private Dictionary<string, List<string>> Deserialize ( XElement xml ) {
			Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>();

			foreach ( var entry in xml.Elements( "Entry" ) ) {
				string key = entry.Element( "Key" ).Value;
				List<string> values = new List<String>();
				dictionary[key] = values;

				foreach ( XElement value in entry.Elements( "Value" ) ) {
					values.Add( value.Value );
				}
			}

			return dictionary;
		} 
		#endregion
	}
}
